<script setup lang="ts">
import { ref, onMounted, nextTick, onUnmounted } from "vue";
import { useRoute, useRouter } from "vue-router";
//
import { formatDate } from "@/utils/format";
// api
import { getArticleByID, deleteArticle } from "@/service/article";
import { getUserInfoByID } from "@/service/user";
// store
import type { IArticle, IuserInfo } from "@/store";
import user from "@/store/user";
import UserInfo from "@/components/UserInfoSide/UserInfoSide.vue";
import local from "@/utils/local";
import { IServiceResult } from "@/service";
import { ElMessage, ElMessageBox, ElImage } from "element-plus";

const route = useRoute();
const router = useRouter();
const userStore = user();
const article = ref<IArticle>();
const previewRef = ref();
const detailRef = ref<HTMLDivElement>();
const navBarRef = ref<HTMLDivElement>();
const navTitles = ref<any[]>([]);
const currentIndex = ref<number>(0);
// 用户信息
const info = ref<IuserInfo>();
const isShow = ref(true);
// 删除文章
const deleteArticleClick = async () => {
  ElMessageBox.confirm("确认删除此文章吗?", "删除文章", {
    cancelButtonText: "取消",
    confirmButtonText: "确认",
    type: "warning"
  })
    .then(async () => {
      const res: IServiceResult = (await deleteArticle(
        article.value!.id
      )) as IServiceResult;
      if (res.code === 0) {
        ElMessage({
          message: res.data.msg,
          type: "success"
        });
        router.replace("/");
      }
    })
    .catch(() => {
      ElMessage({
        message: "该操作已取消",
        type: "info"
      });
    });
};
// 点击跳转标签导航
const handleAnchorClick = (anchor: any) => {
  const { lineIndex } = anchor;
  const heading = previewRef.value.$el.querySelector(
    `[data-v-md-line="${lineIndex}"]`
  );
  if (heading) {
    document.documentElement.scrollTop = heading.offsetTop;
  }
};

// 滚动到对应标题高亮
const titleScrollHeight = () => {
  // 查找当前滚动到哪个标提的位置
  const DSC = document.documentElement.scrollTop;
  let current = 0;
  current = navTitles.value.findIndex(item => item.el.offsetTop >= DSC);
  // 以防赋值过多
  if (current != currentIndex.value && current !== -1) {
    if (current >= navTitles.value.length - 1 || current === -1) {
      currentIndex.value = navTitles.value.length - 1;
    } else {
      currentIndex.value = current;
    }
    // 用户信息展示
    if (isShow.value && DSC >= navBarRef.value!.offsetTop) {
      isShow.value = false;
    } else if (!isShow.value && DSC <= navBarRef.value!.clientHeight) {
      isShow.value = true;
    }

    // 滚动
    detailRef.value &&
      (detailRef.value.scrollTop = currentIndex.value * 30 - 120);
    navBarRef.value &&
      (navBarRef.value.scrollTop = currentIndex.value * 30 - 120);
  }
};

// 点击放大图片
const imageUrl = ref<string>("");
const showImageDialog = ref(false);
function imageClick(images: string[], currentIndex: number) {
  console.log(images);

  imageUrl.value = images[currentIndex];
  showImageDialog.value = true;
}
// 获取渲染的标题列表
const getArticleDataAndRenderTitle = async () => {
  // // 增加阅读
  const infoResult: any = await getUserInfoByID(route.query.uid as string);
  info.value = infoResult.data;
  // 保留( 更新信息)
  if (route.query.uid === userStore.userInfo?.id) {
    userStore.userInfo = {
      ...infoResult.data,
      token: userStore.userInfo?.token
    };
  }
  // 获取文章内容
  const res: any = await getArticleByID(route.query.id as string);
  article.value = res.data.article as IArticle;

  // // 设置文章的标题
  document.title = article.value.title;

  nextTick(() => {
    const anchors = previewRef.value?.$el.querySelectorAll("h1,h2,h3,h4,h5,h6");
    console.log(anchors);
    const titles = Array.from(anchors).filter(
      (title: any) => !!title.innerText.trim()
    );
    if (!titles.length) {
      navTitles.value = [];
      return;
    }
    const hTags = Array.from(
      new Set(titles.map((title: any) => title.tagName))
    ).sort();
    navTitles.value = titles.map((el: any) => ({
      title: el.innerText,
      lineIndex: el.getAttribute("data-v-md-line"),
      indent: hTags.indexOf(el.tagName),
      el
    }));
  });
  window.addEventListener("scroll", titleScrollHeight);
};

// 编辑文章的点击
const editClick = () => {
  local.set("edit-article", article.value);
  router.push("/editarticle");
};
// 挂载钩子  执行数据获取
onMounted(() => {
  getArticleDataAndRenderTitle();
});
// 卸载滚动 匹配标题的事件
onUnmounted(() => {
  window.removeEventListener("scroll", titleScrollHeight);
  document.body.title = "个人博客";
});
</script>

<template>
  <div class="readview-container">
    <div class="readview" v-if="article">
      <h1 class="title">{{ article.title }}</h1>
      <div class="info">
        <div class="info-left">
          <img class="img" v-lazy="article.avatarUrl" alt="" />
          <div class="username">
            <div class="name">{{ article.username }}</div>
            <div class="time">
              {{ formatDate(article.createTime) }} . 阅读 {{ article.read }}
            </div>
          </div>
        </div>
        <div class="operate" v-if="article.uid === userStore.userInfo?.id">
          <span @click="editClick">编辑</span> |
          <span @click="deleteArticleClick">删除</span>
        </div>
        <div v-else gclass="operate"><el-button>关注</el-button></div>
      </div>
      <el-image
        class="cover"
        style="width: 100%"
        :src="article?.cover"
        :preview-src-list="[article?.cover]"
        fit="cover"
      />
      <v-md-editor
        ref="previewRef"
        @image-click="imageClick"
        :model-value="article?.content"
        mode="preview"
      ></v-md-editor>
      <template v-for="tag in article.tags">
        <el-tag style="margin: 10px 10px 0 0">{{ tag }}</el-tag>
      </template>

      <div class="article-operate">
        <div class="left">
          <img :src="article.avatarUrl" alt="" />
          <span>{{ article.username }}</span>
        </div>
        <div class="right"></div>
      </div>
    </div>

    <div class="user-detail-info" ref="detailRef">
      <UserInfo v-if="isShow" :uid="article?.uid" :user-info="info" />
      <div class="navBar" ref="navBarRef">
        <h1 v-show="navTitles.length" class="title">目录</h1>
        <div
          v-for="(anchor, index) in navTitles"
          :class="[currentIndex === index ? 'navTitleActie' : 'navTitle']"
          @click="handleAnchorClick(anchor)"
        >
          <a
            :style="{
              cursor: 'pointer',
              paddingLeft: `${anchor.indent * 20}px`,
              color: index === currentIndex ? '#1E80FF' : ''
            }"
            >{{ anchor.title }}</a
          >
        </div>
      </div>
    </div>
    <el-dialog v-model="showImageDialog" width="100%">
      <el-image
        style="width: 100%"
        :src="imageUrl"
        :preview-src-list="[imageUrl]"
        :initial-index="4"
        fit="cover"
      />
    </el-dialog>
  </div>
</template>

<style scoped lang="less">
:deep(.el-dialog) {
  width: 60% !important;
  user-select: none;
}
:deep(.vuepress-markdown-body) {
  margin-bottom: 0 !important;
}
.cover {
  width: 100%;
  height: 300px;
  margin-top: 10px;
  border-radius: 10px;
}
.readview-container {
  position: relative;
  width: 1240px;
  display: flex;
  box-sizing: border-box;
  .user-detail-info {
    position: sticky;
    top: 75px;
    right: -10px;
    margin-top: 75px;
    width: 23%;
    height: fit-content;
    margin-left: 10px;
    transition: all 0.3s linear;
    text-align: center;
    padding: 0 10px;
    user-select: auto;
    :deep(.user-card-container) {
      .iconfont {
        padding: 0;
      }
    }

    .navBar {
      position: relative;
      left: 0;
      height: fit-content;
      padding: 0 10px;
      max-height: 450px;
      margin-top: 10px;
      transition: all 0.3s linear;
      overflow-y: auto;
      box-shadow: 0 0 5px rgba(0, 0, 0, 0.4);
      border-radius: 10px;
      background-color: #fff;

      .title {
        font-weight: 500;
        padding: 10px 0px 5px;
        margin-bottom: 5px;
        border-bottom: 1px solid #ccc;
      }
      div {
        padding: 0 20px;
        a {
          font-size: 12px;
          height: 30px;
          line-height: 30px;
          overflow: hidden;
          text-overflow: ellipsis; /* 弹性伸缩盒子模型显示*/
          display: -webkit-box;
          /* 限制在一个块元素显示的文本的行数*/
          -webkit-line-clamp: 1;
          /*大设置或检索伸缩盒对象的子元素的排列方式*/
          -webkit-box-orient: vertical;
        }
      }
    }
  }

  .readview {
    flex: 1;
    margin-top: 75px;
    padding: 30px 20px 10px;
    background-color: white;
    box-shadow: 0 0 3px rgba(0, 0, 0, 0.4);
    border-radius: 5px;
    display: inline-block;
    .title {
      margin: 0 0 20px;
      font-size: 30px;
      font-weight: 600;
      line-height: 1.31;
      color: #252933;
    }
    .info {
      display: flex;
      align-items: center;
      justify-content: space-between;
      width: 100%;
      height: 40px;
      margin-bottom: 10px;
      .operate {
        span {
          &:hover {
            color: #1e80ff;
            cursor: pointer;
          }
        }
      }
      .info-left {
        display: flex;
        .img {
          width: 40px;
          height: 40px;
          margin-right: 10px;
          border-radius: 50%;
          vertical-align: middle;
        }
        .username {
          display: flex;
          flex-direction: column;
          justify-content: space-around;
          height: 40px;
          font-size: 15px;
          .name {
            color: #515767;
          }
          .time {
            color: #8a919f;
          }
        }
      }
    }
    .article-operate {
      margin: 10px 0;
      .left {
        img {
          width: 50px;
          height: 50px;
          border-radius: 50%;
          object-fit: cover;
          vertical-align: middle;
          margin-right: 10px;
        }
      }
    }
  }
}
</style>
